<script setup lang="ts">
import { Delete, Plus, QuestionFilled, Switch } from '@element-plus/icons-vue'
import { isEmpty, noop } from 'lodash-es'
import useTextToImageGeneration from './useTextToImageGeneration'
import { dayjs, FormInstance, FormRules } from 'element-plus'
import { ApiDetail } from '@/api/api-manage/detail'
import { message } from '@/utils/message'
import { addLog } from '@/api/api-manage/log'
import { useUserStore } from '@/store/modules/user'
import { getToken } from '@/utils/auth'
import { generateApiLog } from '@/views/trial/useApiLog'

const props = defineProps<{
  data: ApiDetail
}>()

const {
  authToken,
  formData,
  modelOptions,
  dialogImageUrl,
  fileList,
  generatedImages,
  generatePictureNumber,
  genRatioOptions,
  genSizeOptions,
  imageStyle,
  imageTotal,
  impactWeight,
  impactWeightImageUrl,
  materialUploadTab,
  previewDialogVisible,
  previewGenerateIndex,
  showImageMask,
  size,
  sizeStyle,
  uploadMaterialDialogVisible,
  uploadRef,
  uploadUrl,
  beforeUpload,
  downloadAllImages,
  handleClickTask,
  handleClose,
  handleConfirm,
  handleDeleteImg,
  handleDeleteImageWeight,
  handleGenerate,
  handleImageStyle,
  handleMoveEnter,
  handleMoveOut,
  handlePictureCardPreview,
  handleRemove,
  handleSizeStyleChange,
  handleSuccess,
  showDialog,
} = useTextToImageGeneration()

const formRules: FormRules = {
  modelName: [{ required: true, message: '请选择模型' }],
  prompt: [{ required: true, message: '请输入题词' }],
}
const formRef = ref<FormInstance>(null!)

async function onGenerate() {
  if (props.data.enabledStatus != '1') {
    message('接口已停用, 请联系管理员开启', { type: 'warning' })
    return
  }
  const ok = await formRef.value.validate().catch(noop)
  if (!ok) return

  let startTime = performance.now()
  const requestTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
  let res = '1'
  let resCode = 200
  handleGenerate()
    .catch((err) => {
      res = '0'
      resCode = 500
    })
    .finally(() => {
      let endTime = performance.now()
      let duration = endTime - startTime
      const endDateTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
      let userBy = '在线体验'
      if (getToken() != null && getToken() != '') {
        userBy = useUserStore().username + userBy
      }
      const log = generateApiLog(
        props.data,
        requestTime,
        endDateTime,
        duration,
        userBy,
        res,
        resCode,
        '2'
      )
      addLog(log)
    })
}
</script>

<template>
  <div class="flex gap-2">
    <div class="w-[360px] px-2">
      <el-form ref="formRef" label-position="top" :model="formData" :rules="formRules">
        <el-form-item prop="modelName" label="模型选择">
          <el-select v-model="formData.modelName">
            <el-option v-for="v in modelOptions" :key="v.name" :label="v.alias" :value="v.name" />
          </el-select>
        </el-form-item>
        <el-form-item prop="prompt" label="创意文字">
          <el-input
            v-model="formData.prompt"
            show-word-limit
            placeholder="请详细地描述脑海中的场景，AI为您生成创意画作。"
            resize="none"
            type="textarea"
            :rows="5"
            :maxlength="190"
          />
        </el-form-item>
        <el-form-item label="风格选择">
          <div class="form-item_content">
            <div class="image-styles">
              <div class="style-item__wrapper">
                <div
                  class="image-style"
                  :class="{ active: imageStyle == '' }"
                  @click="handleImageStyle('')"
                >
                  <img
                    class="img"
                    src="@/assets/images/aigc/intelligent-recommendation.jpeg"
                    alt=""
                    srcset=""
                  />
                </div>
                <div class="txt">智能推荐</div>
              </div>
              <div class="style-item__wrapper">
                <div
                  class="image-style"
                  :class="{ active: imageStyle == '艺术创想' }"
                  @click="handleImageStyle('艺术创想')"
                >
                  <img class="img" src="@/assets/images/aigc/artistic-idea2.jpg" alt="" srcset="" />
                </div>
                <div class="txt">艺术创想</div>
              </div>
              <div class="style-item__wrapper">
                <div
                  class="image-style"
                  :class="{ active: imageStyle == '中国风' }"
                  @click="handleImageStyle('中国风')"
                >
                  <img class="img" src="@/assets/images/aigc/chinese-style2.jpg" alt="" srcset="" />
                </div>
                <div class="txt">中国风</div>
              </div>
              <div class="style-item__wrapper">
                <div
                  class="image-style"
                  :class="{ active: imageStyle == '二次元' }"
                  @click="handleImageStyle('二次元')"
                >
                  <img
                    class="img"
                    src="@/assets/images/aigc/beautiful-two-dimensional2.jpg"
                    alt=""
                    srcset=""
                  />
                </div>
                <div class="txt">二次元</div>
              </div>
              <div class="style-item__wrapper">
                <div
                  class="image-style"
                  :class="{ active: imageStyle == '朋克' }"
                  @click="handleImageStyle('朋克')"
                >
                  <img class="img" src="@/assets/images/aigc/cyberpunk2.jpg" alt="" srcset="" />
                </div>
                <div class="txt">朋克</div>
              </div>
              <div class="style-item__wrapper">
                <div
                  class="image-style"
                  :class="{ active: imageStyle == '插画' }"
                  @click="handleImageStyle('插画')"
                >
                  <img
                    class="img"
                    src="@/assets/images/aigc/concept-illustration2.jpg"
                    alt=""
                    srcset=""
                  />
                </div>
                <div class="txt">插画</div>
              </div>
            </div>
          </div>
        </el-form-item>
        <el-form-item label="上传参考图">
          <div v-if="impactWeightImageUrl" class="reference-image-out-wrapper w-full flex-1">
            <div
              class="reference-image-wrapper w-full flex-1"
              @mousemove="handleMoveEnter"
              @mouseout="handleMoveOut"
            >
              <div v-show="showImageMask" class="mask" />
              <img :src="impactWeightImageUrl" alt="" class="reference-iamge" />
              <span v-show="showImageMask" class="anticon replace-icon" @click="showDialog">
                <el-icon><Switch /></el-icon>
              </span>
              <span
                v-show="showImageMask"
                class="anticon delete-icon"
                @click="handleDeleteImageWeight"
              >
                <el-icon><Delete /></el-icon>
              </span>
            </div>
            <div class="impact-weight-wrapper">
              <div class="impact-weight-desc">
                <span>影响比重</span>
                <span>
                  <el-tooltip
                    class="box-item"
                    effect="dark"
                    content="数值越大，结果与参考图的相似度越高"
                    placement="top"
                  >
                    <el-icon><QuestionFilled /></el-icon>
                  </el-tooltip>
                </span>
              </div>
              <div class="impact-weight-slider-label">
                <span>1</span>
                <span>10</span>
              </div>
              <el-slider v-model="impactWeight" :min="1" :max="10" />
            </div>
          </div>
          <div v-else class="limitation-wrapper gap-2" @click="showDialog">
            <el-icon :size="20"><Plus /></el-icon>
            <div class="limitation-desc">支持JPT、PNG，不超过7MB</div>
            <div class="limitation-desc">图片宽高需在15px和8192px之间</div>
          </div>
        </el-form-item>
        <el-dialog
          v-model="uploadMaterialDialogVisible"
          title="素材选择与上传"
          width="60%"
          :before-close="handleClose"
        >
          <el-tabs v-model="materialUploadTab">
            <el-tab-pane label="本地上传" name="local">
              <el-upload
                ref="uploadRef"
                v-model:file-list="fileList"
                :action="uploadUrl"
                :headers="{
                  Authorization: 'Bearer ' + authToken,
                }"
                list-type="picture-card"
                :limit="1"
                :before-upload="beforeUpload"
                :on-preview="handlePictureCardPreview"
                :on-success="handleSuccess"
                :on-remove="handleRemove"
              >
                <el-button type="primary">点击上传</el-button>
                <template #tip>
                  <div class="el-upload__tip">支持JPG、PNG，单个文件不超过7MB</div>
                  <div class="el-upload__tip">宽高需在15px和8192px之间</div>
                </template>
              </el-upload>

              <el-dialog v-model="previewDialogVisible">
                <img w-full :src="dialogImageUrl" alt="Preview Image" />
              </el-dialog>
            </el-tab-pane>
          </el-tabs>
          <template #footer>
            <div class="dialog-footer">
              <el-button @click="handleClose">取 消</el-button>
              <el-button type="primary" @click="handleConfirm">确 定</el-button>
            </div>
          </template>
        </el-dialog>
        <el-form-item label="尺寸选择">
          <el-row class="w-full" :gutter="8">
            <el-col :span="12">
              <el-select v-model="sizeStyle" @change="handleSizeStyleChange">
                <el-option
                  v-for="v in genRatioOptions"
                  :key="v.value"
                  :label="v.label"
                  :value="v.value"
                >
                  {{ v.label }}
                </el-option>
              </el-select>
            </el-col>
            <el-col :span="12">
              <el-select v-model="size">
                <el-option
                  v-for="v in genSizeOptions"
                  :key="v.value"
                  :label="v.label"
                  :value="v.value"
                >
                  {{ v.label }}
                </el-option>
              </el-select>
            </el-col>
          </el-row>
        </el-form-item>
        <el-form-item label="生成数量">
          <el-slider v-model="generatePictureNumber" class="ml-4" :min="1" :max="8" show-input />
        </el-form-item>
      </el-form>
      <div class="generate-btn">
        <el-button type="primary" size="small" @click="onGenerate">一键生成</el-button>
      </div>
    </div>
    <div class="flex-1">
      <!-- <div class="title">左侧输入描述，开启AI作画之旅吧</div> -->
      <div class="editor-preview-wrapper">
        <div class="preview-wrapper">
          <div v-if="generatedImages.length > 0" class="grid grid-cols-4 gap-2">
            <div
              v-for="(item, index) in generatedImages[previewGenerateIndex].imgList"
              :key="index"
              class="preview-grid-area"
            >
              <div class="preview-image">
                <el-image :src="item.url" :preview-src-list="[item.url]" />
              </div>
            </div>
          </div>
          <div class="outer-wrapper">
            <div class="operation-wrapper">
              <div class="work-count">作品数量（{{ imageTotal }}）</div>
              <div>
                <el-button
                  type="primary"
                  :disabled="isEmpty(generatedImages)"
                  @click="downloadAllImages"
                >
                  下载全部
                </el-button>
                <el-button type="danger" @click="handleDeleteImg">删除</el-button>
              </div>
            </div>
            <div class="divider" />
            <div class="task-list-wrapper">
              <template v-for="(item, index) in generatedImages">
                <div
                  v-if="item.imgList.length > 0"
                  :key="index"
                  class="task-wrapper"
                  :class="[
                    index == previewGenerateIndex ? 'active' : '',
                    item.imgList.length > 1 ? 'multiple' : '',
                  ]"
                  @click="handleClickTask(index, item)"
                >
                  <img :src="item.imgList[0].url" alt="" class="preview-image" loading="lazy" />
                  <span class="generation-image-count">{{ item.imgList.length }}</span>
                </div>
              </template>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.reference-image-out-wrapper {
  display: flex;

  .reference-image-wrapper {
    background-color: #e8e9eb;
    border-radius: 4px;
    display: flex;
    height: 72px;
    justify-content: center;
    position: relative;

    .mask {
      background-color: #070c14;
      border-radius: 4px;
      height: 100%;
      left: 0;
      opacity: 0.5;
      position: absolute;
      top: 0;
      width: 100%;
    }

    .reference-image {
      border-radius: 4px;
      max-height: 100%;
      max-width: 100%;
    }

    .anticon {
      color: #fff;
      cursor: pointer;
      font-size: 14px;
      left: 60%;
      margin-left: 4px;
      position: absolute;
      top: 50%;
      transform: translate(-50%, -50%);
      z-index: 2;

      &.replace-icon {
        left: 40%;
      }

      &.delete-icon {
        left: 60%;
      }
    }
  }

  .impact-weight-wrapper {
    display: flex;
    flex: 1;
    flex-direction: column;
    margin-left: 16px;
    min-width: 0;

    .impact-weight-desc {
      align-items: center;
      color: #84868c;
      display: flex;
      font-size: 12px;
      margin-bottom: 10px;
    }

    .impact-weight-slider-label {
      display: flex;
      justify-content: space-between;
      font-size: 12px;
    }
  }
}

.limitation-wrapper {
  width: 100%;
  align-items: center;
  border: 1px dashed #e8e9eb;
  border-radius: 4px;
  color: #84868c;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  font-size: 12px;
  justify-content: center;
  padding: 16px 0;
}

.pic-grid-wrapper {
  display: grid;
  gap: 16px;
  grid-template-columns: repeat(4, 1fr);

  .pic-grid-area {
    position: relative;

    .custom-checkbox-wrapper {
      position: absolute;
      left: 2px;
      width: 14px;

      &.is-checked {
        .custom-checkbox__inner {
          background-color: #409eff;
          border-color: #409eff;

          &::after {
            transform: rotate(45deg) scaleY(1);
          }
        }
      }

      .custom-checkbox__inner {
        display: inline-block;
        position: relative;
        border: 1px solid #dcdfe6;
        border-radius: 2px;
        box-sizing: border-box;
        width: 14px;
        height: 14px;
        background-color: #ffffff;
        z-index: 1;
        transition:
          border-color 0.25s cubic-bezier(0.71, -0.46, 0.29, 1.46),
          background-color 0.25s cubic-bezier(0.71, -0.46, 0.29, 1.46),
          outline 0.25s cubic-bezier(0.71, -0.46, 0.29, 1.46);

        &::after {
          box-sizing: content-box;
          content: '';
          border: 1px solid #ffffff;
          border-left: 0;
          border-top: 0;
          height: 7px;
          left: 4px;
          position: absolute;
          top: 1px;
          transform: rotate(45deg) scaleY(0);
          width: 3px;
          transition: transform 0.15s ease-in 50ms;
          transform-origin: center;
        }
      }
    }
  }
}

.editor-preview-wrapper {
  display: flex;
  height: 100%;

  .preview-wrapper {
    display: flex;
    flex: 1;
    flex-direction: column;

    .preview-grid {
      margin-bottom: var(--el-main-padding);
      padding: 16px;
      display: grid;
      gap: 16px;
      background-color: #ffffff;
      min-height: 200px;

      .preview-grid-area {
        display: flex;
        justify-content: center;

        .preview-image {
          // aspect-ratio: 1 / 1;
          max-width: min(100%, 512px);
          // max-height: min(100%, 512px);
          border-radius: 6px;
          position: relative;
        }
      }
    }

    .outer-wrapper {
      background-color: #fff;
      border-radius: 6px;
      display: flex;
      flex: 0 0 235px;
      flex-direction: column;
      min-height: 0;
      padding: 16px 16px 14px;

      .operation-wrapper {
        align-items: center;
        display: flex;
        justify-content: space-between;

        .work-count {
          color: #151b26;
        }
      }

      .divider {
        background-color: #e8e9eb;
        height: 1px;
        margin: 16px 0;
      }

      .task-list-wrapper {
        display: flex;
        overflow-x: auto;
        overflow-y: hidden;
        // padding: 16px 0 2px;

        .task-wrapper {
          align-items: center;
          border-radius: 6px;
          cursor: pointer;
          display: flex;
          flex: 0 0 130px;
          justify-content: center;
          margin-right: 16px;
          position: relative;
          margin-top: 6px;

          &.active {
            outline: 3px solid #2468f2;
            outline-offset: -3px;
          }

          &:last-child {
            margin-right: 0;
          }

          .preview-image {
            border-radius: 6px;
            height: 100%;
            object-fit: cover;
            width: 100%;
          }

          .generation-image-count {
            background-color: #2468f2;
            border-bottom-left-radius: 4px;
            border-top-right-radius: 4px;
            color: #fff;
            height: 20px;
            position: absolute;
            right: 0;
            top: 0;
            width: 44px;

            align-items: center;
            display: flex;
            justify-content: center;
          }
        }
        .task-wrapper.multiple {
          &::before,
          &::after {
            background-color: transparent;
            border-radius: 4px;
            border-top: 3px solid #ccc;
            content: '';
            display: block;
            height: 100%;
            left: 50%;
            position: absolute;
            transform: translateX(-50%);
            width: 90%;
            top: -3px;
          }
          &::after {
            top: -6px;
            width: 110px;
          }
        }
      }
    }
  }

  .outer-wrapper {
    display: flex;
    flex-direction: column;
    flex: 0 0 235px;
    background-color: #ffffff;
  }
}

.el-main {
  .title {
    margin-top: 270px;
    text-align: center;
    color: #b8babf;
    font-size: 24px;
  }
}

.generate-btn .el-button {
  color: #fff;
  background-color: #2468f2;
  border-color: #2468f2;
  width: 100%;
  padding: 16px 0;
}

.image-styles {
  width: 100%;
  display: grid;
  flex-wrap: wrap;
  gap: 12px 8px;
  grid-template-columns: repeat(4, 1fr);
}

.style-item__wrapper {
  text-align: center;
  cursor: pointer;
}

.image-style {
  border-radius: 4px;
}

.image-style.active {
  outline: 2px solid #2468f2;
}

.image-style .img {
  border-radius: 4px;
  max-width: 100%;
}

.style-item__wrapper .txt {
  color: #151b26;
  font-size: 12px;
  margin-top: 4px;
}
</style>
